package mongodb.general.operator.nodb.vo;


import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 处理请求参数
 *
 * @author YCKJ4182
 * @since 2021/12/08/ 17:27
 */
@Slf4j
public class MongoRequestParamsHandler {

    // 模糊查询字段列表
    private List<String> queryFuzzList;
    // 区间查询
    private List<String> queryRangeList;
    // 非空查询
    private List<String> notNullList;
    // 空值查询
    private List<String> nullList;
    // 表名
    private String tableName = "big_person_info";
    // 需要返回的参数列表
    private List<String> responseParameters;
    // 构造请求条件的参数
    private Map<String, Object> paramsMap;
    // 排序
    private Map<String, Object> sortBy;
    // $in操作字段
    private List<String> inOperationList;
    /**
     * $or操作字段
     * 字段值不是从paramsMap中获取，而是直接在此list中定义(同一属性可以有多个条件) 如：
     * 查询年龄12或者15岁 并且 名字为张三或李四的人
     {"data":{"serviceName":"timo_test","orOperationList":[[{"key":"age","val":"20","way":"eq"},{"key":"age","val":"14","way":"eq"}],[{"key":"name","val":"张","way":"like"},{"key":"name","val":"三","way":"like"}]]}}
     {"data":{"serviceName":"yqfk_person_info","orOperationList":[[{"key":"name","val":"736756789","way":"like"},{"key":"cardNo","val":"736756789","way":"like"},{"key":"mobile","val":"736756789","way":"like"}]]}}
     */
    private List<List<Map<String, Object>>> orOperationList;
    //
    private String eventNameUnwind;

    private Map<String, String> queryRangeType;

    private Integer currentPage = 1;

    private Integer pageSize = 10;

    public int getCurrentPage() {
        return currentPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public MongoRequestParamsHandler(Object infoDto) throws Exception {
        Map<String, Object> infoMap = (Map) infoDto;
        Field[] declaredFields = MongoRequestParamsHandler.class.getDeclaredFields();
        for (Field field : declaredFields) {
            String fieldName = field.getName();
            Class<?> fieldType = field.getType();
            Object fieldValue = infoMap.get(fieldName);
            if (fieldValue != null) {
                // 检验参数类型
                validParam(fieldValue, fieldType, fieldName);
                field.setAccessible(true);
                field.set(this, fieldValue);
                // 只保留查询条件字段
                infoMap.remove(fieldName);
            }
        }
        this.paramsMap = infoMap;
        infoMap.put("delFlag", 0);
    }

    private static void validParam(Object o, Class<?> clazz, String paramName) throws Exception {
        if (!clazz.isAssignableFrom(o.getClass())) {
            throw new Exception("参数" + paramName + "类型有误。");
        }
    }

    public boolean isFuzz(String key) {
        if (queryFuzzList != null && queryFuzzList.contains(key)) {
            return true;
        }
        return false;
    }

    public boolean isRange(String key) {
        if (queryRangeList != null && queryRangeList.contains(key)) {
            return true;
        }
        return false;
    }

    public String getType(String key){
        if(queryRangeType != null && queryRangeType.containsKey(key))
        {
         return queryRangeType.get(key);
        }
        return null;
    }

    public boolean isInOperation(String key) {
        if (inOperationList != null && inOperationList.contains(key)) {
            return true;
        }
        return false;
    }


    public List<List<Map<String, Object>>> getOrOperationList() {
        return orOperationList;
    }

    public void setOrOperationList(List<List<Map<String, Object>>> orOperationList) {
        this.orOperationList = orOperationList;
    }

    public Map<String, Object> getParamsMap() {
        return paramsMap;
    }

    public boolean isSubListField(String key) {
        return paramsMap.get(key) instanceof List;
    }

    public List<String> getResponseParameters() {
        return responseParameters;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public Map<String, Object> getSortBy() {
        return sortBy == null ? new HashMap<>() : sortBy;
    }

    public List<String> getInOperationList() {
        return inOperationList == null ? new ArrayList<>() : inOperationList;
    }

    public String getEventNameUnwind() {
        return eventNameUnwind;
    }


    public static Criteria getCriteriaFromQuery(Query query) {
        Document document = query.getQueryObject();
        Criteria c = new Criteria();
        try {

            Field _criteria = c.getClass().getDeclaredField("criteria");
            _criteria.setAccessible(true);

            @SuppressWarnings("unchecked")
            LinkedHashMap<String, Object> criteria = (LinkedHashMap<String, Object>) _criteria.get(c);

            for (Map.Entry<String, Object> set : document.entrySet()) {
                criteria.put(set.getKey(), set.getValue());
            }

            Field _criteriaChain = c.getClass().getDeclaredField("criteriaChain");
            _criteriaChain.setAccessible(true);

            @SuppressWarnings("unchecked")
            List<Criteria> criteriaChain = (List<Criteria>) _criteriaChain.get(c);
            criteriaChain.add(c);

        } catch (Exception e) {
            // Ignore
        }

        return c;
    }

    public Sort getSortObject() {
        if (sortBy == null || sortBy.isEmpty()) {
            return Sort.unsorted();
        }
        List<Sort.Order> orderList = new ArrayList<>();
        sortBy.forEach((k, v) -> {
            Sort.Order orderK = (Integer) v == 1 ? Sort.Order.asc(k) : Sort.Order.desc(k);
            orderList.add(orderK);
        });
        return Sort.by(orderList);
    }

    public boolean isNotNull() {
        if (notNullList != null) {
            return true;
        }
        return false;
    }

    public boolean isNull() {
        if (nullList != null) {
            return true;
        }
        return false;
    }

    public void setNotNullList(List<String> notNullList) {
        this.notNullList = notNullList;
    }

    public List<String> getNotNullList() {
        return notNullList;
    }

    public void setNullList(List<String> nullList) {
        this.nullList = nullList;
    }

    public List<String> getNullList() {
        return nullList;
    }


}
